package cn.bonoon.kernel.support.services.handler;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import cn.bonoon.kernel.support.entities.EntityMovable;
import cn.bonoon.kernel.support.entities.EntityTree;

public class OperateTreeInHandler<E extends EntityTree<E>> extends AbstractTreeMovableHandler<E>{

	private final String maxChildrenOrdinal;
	private final String preRootOrdinal;
	private final String preChildrenOrdinal;
	public OperateTreeInHandler(Class<E> entityClass) {
		super(entityClass);
		String entityName = entityClass.getName();
		maxChildrenOrdinal = "select x.ordinal from " + entityName + " x where x.parent.id=? order by x.ordinal desc";
		preRootOrdinal = "select x from "+ entityName + " x where x.parent is null and x.ordinal<? order by x.ordinal desc";
		preChildrenOrdinal = "select x from "+ entityName + " x where x.parent.id=? and x.ordinal<? order by x.ordinal desc";
	}

//	@Override
//	public Object handler(OperateSource service, OperateEvent event, Long id) {
//		EntityManager entityManager = service.getEntityManager();
//		E node = entityManager.find(entityClass, id);
//		E oldParent = node.getParent();
//		if(null == oldParent){
//			E newParent = get(entityManager.createQuery(preRootOrdinal, entityClass)
//					.setParameter(1, ((EntityMovable)node).getOrdinal()));
//			if(null != newParent){
//				move(node, newParent, entityManager);
//			}
//		}else{
//			E newParent = get(entityManager.createQuery(preChildrenOrdinal, entityClass)
//					.setParameter(1, oldParent.getId())
//					.setParameter(2, ((EntityMovable)node).getOrdinal()));
//			if(null != newParent){
//				move(node, newParent, entityManager);
//				oldParent.setSize(oldParent.getSize() - 1);
//				entityManager.merge(oldParent);
//			}
//		}
//		return null;
//	}
	
	@Override
	protected Object move(E source, EntityManager entityManager) {
		E newParent = get(entityManager.createQuery(preRootOrdinal, entityClass)
				.setParameter(1, ((EntityMovable)source).getOrdinal()));
		if(null != newParent){
			move(source, newParent, entityManager);
		}
		return null;
	}
	
	@Override
	protected Object move(E source, EntityManager entityManager, E oldParent) {
		E newParent = get(entityManager.createQuery(preChildrenOrdinal, entityClass)
				.setParameter(1, oldParent.getId())
				.setParameter(2, ((EntityMovable)source).getOrdinal()));
		if(null != newParent){
			move(source, newParent, entityManager);
			oldParent.setSize(oldParent.getSize() - 1);
			entityManager.merge(oldParent);
		}
		return null;
	}
	
	private Integer getOrdinal(TypedQuery<Integer> tqSelect){
		List<Integer> list = tqSelect.setMaxResults(1).getResultList();
		if(list.size() == 1){
			return list.get(0);
		}
		return null;
	}
	
	@Override
	protected void move(E source, E target, EntityManager entityManager, E oldSourceParent) {
		if(!oldSourceParent.getId().equals(target.getId())){
			move(source, target, entityManager);
			oldSourceParent.setSize(oldSourceParent.getSize() - 1);
			entityManager.merge(oldSourceParent);
		}
	}
	
	protected void move(E node, E newParent, EntityManager entityManager){
		newParent.setSize(newParent.getSize() + 1);
		entityManager.merge(newParent);
		Integer max = getOrdinal(entityManager.createQuery(maxChildrenOrdinal, Integer.class).setParameter(1, newParent.getId()));
		if(null == max){
			((EntityMovable)node).setOrdinal(1);
		}else{
			((EntityMovable)node).setOrdinal(max + 1);
		}
		node.setParent(newParent);
		node.setFullName(newParent.getFullName() + node.getName());
		node.setXpath(newParent.getXpath() + node.getId() + '/');
		entityManager.merge(node);
		updateChildren(entityManager, node);
	}
}
